package net.zbus;

import net.zbus.ZMQ.Context;

import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.log4j.Logger;

public class ClientPool {
	protected Context ctx;
	protected GenericObjectPool internalPool;
	protected ClientPoolConfig config;

	public ClientPool(ClientPoolConfig config) {
		this.config = config;
		if(this.config.getCtx() == null){ //no context set create new one
			this.ctx = ZMQ.context(1);
			config.setCtx(this.ctx);
		}
		this.internalPool = new GenericObjectPool(new BusClientFactory(config), config);
	}

	public BusClient borrowClient() {
		try {
			return (BusClient) internalPool.borrowObject();
		} catch (Exception e) {
			throw new ZBusException("Could not get a resource from the pool", e);
		}
	}

	public void returnClient(final BusClient client) {
		try {
			internalPool.returnObject(client);
		} catch (Exception e) {
			throw new ZBusException(
					"Could not return the resource to the pool", e);
		}
	} 
	
	public void destroy() {
		try {
			internalPool.close();
		} catch (Exception e) {
			throw new ZBusException("Could not destroy the pool", e);
		} finally{
			if(this.ctx != null){
				this.ctx.term();
			}
		}
	}
	

	public static void main(String[] args) { 
		ClientPoolConfig config = new ClientPoolConfig(); 
		
		ClientPool pool = new ClientPool(config);
		BusClient client = pool.borrowClient();
		
		ZMsg req = new ZMsg();
		req.pushBack("test");
		ZMsg msg = client.request("helloworld", "", req , 2500);
		msg.dump();
		
		pool.returnClient(client);
		
		pool.destroy();
		 
	}
}

class BusClientFactory extends BasePoolableObjectFactory {
	private ClientPoolConfig config;
	private static final Logger logger = Logger.getLogger(BusClientFactory.class);
	
	public BusClientFactory(ClientPoolConfig config) {
		this.config = config;
	}

	public Object makeObject() throws Exception { 
		return new BusClient(config.getCtx(), config.getHost(),
				config.getPort(), config.getId());
	}

	public void destroyObject(final Object obj) throws Exception {
		if (obj instanceof BusClient) { 
			final BusClient client = (BusClient) obj;
			client.destroy();
		}
	}

	public boolean validateObject(final Object obj) {
		logger.info("validate object...");
		if (obj instanceof BusClient) {
			logger.info("validate object...");
			final BusClient client = (BusClient) obj;
			try {
				int rc = client.probe(2500);
				if (rc != 0) {
					logger.error("validate error");
				}
				return rc == 0;
			} catch (final Exception e) {
				e.printStackTrace();
				logger.error(e.getMessage() , e);
				return false;
			}
		} else {
			return false;
		} 
	} 
}
